﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2024 LiLong                                                   **
**  This file is part of GnssLogs.                                              **
**                                                                              **
**  GnssLogs is free software: you can redistribute it and/or modify            **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  GnssLogs is distributed in the hope that it will be useful,                 **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with GnssLogs.  If not, see <https://www.gnu.org/licenses/>.          **
**********************************************************************************/
#pragma once

#include "../LogHeader.h"
#include "Commons.h"

namespace GnssLogs
{
namespace LogHeaderDecoder
{
// clang-format off
using Sync    = seq<one<'#'>, star<ascii::alnum>>;
struct Message : star<alpha> {};
struct Port : star<digit> {};
struct Sequence : star<digit> {};
struct IdleTime : Floating {};
struct TimeStatus : star<alpha> {};
struct Week : star<digit> {};
struct Seconds : Floating {};
struct ReceiverStatus : star<xdigit> {};
struct Reversed : star<xdigit> {};
struct ReceiverSWVersion : star<digit> {};
struct HeaderEnd : one<';'> {};
// clang-format on
using Expression = seq<Sync,
                       Split,
                       Message,
                       Port,
                       Split,
                       Sequence,
                       Split,
                       IdleTime,
                       Split,
                       TimeStatus,
                       Split,
                       Week,
                       Split,
                       Seconds,
                       Split,
                       ReceiverStatus,
                       Split,
                       Reversed,
                       Split,
                       ReceiverSWVersion,
                       HeaderEnd>;

template<typename _Sync>
using SyncExpression = seq<_Sync,
                           Split,
                           Message,
                           Port,
                           Split,
                           Sequence,
                           Split,
                           IdleTime,
                           Split,
                           TimeStatus,
                           Split,
                           Week,
                           Split,
                           Seconds,
                           Split,
                           ReceiverStatus,
                           Split,
                           Reversed,
                           Split,
                           ReceiverSWVersion,
                           HeaderEnd>;
template<typename _Sync>
struct Action
{
    template<typename ParseInput, typename... Args>
    static bool apply(ParseInput& in, LogHeader::Data& data, Args&... args)
    {
        if (*in.begin() == '#')
            data.sync = std::string(in.begin(), in.size());
        return true;
    }
};

template<>
struct Action<Split>
{
};

template<>
struct Action<Message>
{
    template<typename ParseInput, typename... Args>
    static bool apply(ParseInput& in, LogHeader::Data& data, Args&... args)
    {
        data.message = std::string(in.begin(), in.size());
        return true;
    }
};

template<>
struct Action<Port> : IntHelper<Action<Port>, uint32_t>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, uint32_t value, Args&... args)
    {
        data.port = value;
    }
};

template<>
struct Action<Sequence> : IntHelper<Action<Sequence>, int>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, int value, Args&... args)
    {
        data.sequence = value;
    }
};

template<>
struct Action<IdleTime> : DoubleHelper<Action<IdleTime>>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, double value, Args&... args)
    {
        data.idleTime = value;
    }
};

template<>
struct Action<TimeStatus> : EnumHelper<Action<TimeStatus>, GnssLogs::LogHeader::Data::TimeStatus>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, GnssLogs::LogHeader::Data::TimeStatus value, Args&... args)
    {
        data.timeStatus = value;
    }
};

template<>
struct Action<Week> : IntHelper<Action<Week>, uint32_t>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, uint32_t value, Args&... args)
    {
        data.week = value;
    }
};

template<>
struct Action<Seconds> : DoubleHelper<Action<Seconds>>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, double value, Args&... args)
    {
        data.seconds = value;
    }
};

template<>
struct Action<ReceiverStatus> : IntHelper<Action<ReceiverStatus>, uint32_t, 16>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, uint32_t value, Args&... args)
    {
        data.receiverStatus = value;
    }
};

template<>
struct Action<Reversed> : IntHelper<Action<Reversed>, uint32_t, 16>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, uint32_t value, Args&... args)
    {
        data.reversed = value;
    }
};

template<>
struct Action<ReceiverSWVersion> : IntHelper<Action<ReceiverSWVersion>, uint32_t>
{
    template<typename... Args>
    static void setValue(LogHeader::Data& data, uint32_t value, Args&... args)
    {
        data.receiverSWVersion = value;
    }
};

template<>
struct Action<HeaderEnd>
{
};

template<typename _Sync>
struct Action<SyncExpression<_Sync>>
{
    template<typename Rule,
             apply_mode A,
             rewind_mode M,
             template<typename...>
             class Action,
             template<typename...>
             class Control,
             typename ParseInput,
             typename... States>
    static bool match(ParseInput& in, LogHeader::Data& data, States&&... st)
    {
        try
        {
            return tao::pegtl::match<Rule, A, M, Action, Control>(in, data);
        }
        catch (...)
        {
            return false;
        }
    }
};

struct LogHeaderHelperNoSetValue
{
    template<typename Rule,
             apply_mode A,
             rewind_mode M,
             template<typename...>
             class _Action,
             template<typename...>
             class Control,
             typename ParseInput,
             typename Data,
             typename... States>
    static bool match(ParseInput& in, Data& data, States&&... st)
    {
        try
        {
            return tao::pegtl::match<Rule, A, M, Action, Control>(in, data.header); // 具名要求 data.header
        }
        catch (...)
        {
            return false;
        }
    }
};
} // namespace LogHeaderDecoder
} // namespace GnssLogs